#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "main.h"

int addHaltCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lmanager, struct program * prog) {
            addProgramByte(prog, 0);
            return 0;
}

int addAddCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            addProgramByte(prog, 1);
            return 0;
}

int addSubCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            addProgramByte(prog, 2);
            return 0;
}

int addIncCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            getNextString (writeBuffer, pFile);
            int regType = matchRegister (writeBuffer);
            if (regType == RG_R0) {
                addProgramByte(prog, 3);
            } else if (regType == RG_R1) {
                addProgramByte(prog, 4);
            } else if (regType == RG_INVALID) {
                //error
            }
            return 0;
}

int addDecCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            getNextString (writeBuffer, pFile);
            int regType = matchRegister (writeBuffer);
            if (regType == RG_R0) {
                addProgramByte(prog, 5);
            } else if (regType == RG_R1) {
                addProgramByte(prog, 6);
            } else if (regType == RG_INVALID) {
                //error
            }
            return 0;
}

int addBeepCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            addProgramByte(prog, 7);
            return 0;
}

int addPrintCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            addProgramByte(prog, 8);
            getNextString (writeBuffer, pFile);
            if (isNumber (writeBuffer)) {
                int value;
                sscanf (writeBuffer, "%d", &value);
                addProgramByte(prog, value);
            } else if (isDataAddress (writeBuffer)) {
                int lPos = findLabelByName (lManager, (char*)(writeBuffer + 1));
                addProgramByte(prog, lManager->labels[lPos].value);
            } else {
                //error
            }
            return 0;
}

int addPrintaCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
            addProgramByte(prog, 24);
            getNextString (writeBuffer, pFile);
            if (isNumber (writeBuffer)) {
                int value;
                sscanf (writeBuffer, "%d", &value);
                addProgramByte(prog, value);
            } else if (isDataAddress (writeBuffer)) {
                int lPos = findLabelByName (lManager, (char*)(writeBuffer + 1));
                addProgramByte(prog, lManager->labels[lPos].value);
            } else if (isAsciiString (writeBuffer)) {
                char temp[MAX_STRING_LEN];
                if(getAsciiString (writeBuffer, temp) == 1) {
                    addProgramByte(prog, temp[0]);
                } else {
                    //error
                }
            } else {
                //error
            }
            return 0;
}

int addMovCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
    int movType = 0;
    int machineByte;
    int opByte;
    getNextString (writeBuffer, pFile);
    int rMatch = matchRegister (writeBuffer);
    if (rMatch == RG_R0) {
        machineByte = 9;
    } else if (rMatch == RG_R1) {
        machineByte = 10;
    } else if (findLabelByName(lManager, writeBuffer) != -1) {
        movType = 1;
        int lPos = findLabelByName(lManager, writeBuffer);
        opByte = lManager->labels[lPos].address;
    } else if (isNumber (writeBuffer)) {
        movType = 1;
        int value;
        sscanf (writeBuffer, "%d", &value);
        int lPos = findImmediateLabelByValue (lManager, value);
        opByte = lManager->labels[lPos].address;
    } else {
        //error
    }
    getNextString (writeBuffer, pFile);
    rMatch = matchRegister (writeBuffer);
    if (movType == 0) {
        if(rMatch != RG_INVALID) {
            //error
        } else if (findLabelByName (lManager, writeBuffer) != -1) {
            int lPos = findLabelByName(lManager, writeBuffer);
            opByte = lManager->labels[lPos].address;
        } else if (isNumber (writeBuffer)) {
            int value;
            sscanf (writeBuffer, "%d", &value);
            int lPos = findImmediateLabelByValue (lManager, value);
            opByte = lManager->labels[lPos].address;
        } else if (isAsciiString (writeBuffer)) {
            char temp[MAX_STRING_LEN];
            if(getAsciiString (writeBuffer, temp) == 1) {
                addProgramByte(prog, temp[0]);
            } else {
                //error
            }
        }
    } else if (movType == 1) {
        if(rMatch == RG_INVALID) {
            //error
        } else if (rMatch == RG_R0) {
            machineByte = 11;
        } else if (rMatch == RG_R1) {
            machineByte = 12;
        }
    }
    addProgramByte (prog, machineByte);
    addProgramByte (prog, opByte);
    printf("%d %d\n", machineByte, opByte);
    return 0;
}

int addJmpCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
    addProgramByte (prog, 13);
    getNextString (writeBuffer, pFile);
    if (isDataAddress (writeBuffer)) {
        int lPos = findLabelByName(lManager, (char*)(writeBuffer + 1));
        addProgramByte (prog, lManager->labels[lPos].value);
    } else if (isNumber (writeBuffer)) {
        int value;
        sscanf (writeBuffer, "%d", &value);
        addProgramByte (prog, value);
    } else {
        int lPos = findLabelByName (lManager, writeBuffer);
        if (lPos != -1) {
            addProgramByte (prog, lManager->labels[lPos].value);
        } else {
            //error
        }
    }
    return 0;
}

int addJzCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
    addProgramByte (prog, 14);
    getNextString (writeBuffer, pFile);
    if (isDataAddress (writeBuffer)) {
        int lPos = findLabelByName(lManager, (char*)(writeBuffer + 1));
        addProgramByte (prog, lManager->labels[lPos].value);
    } else if (isNumber (writeBuffer)) {
        int value;
        sscanf (writeBuffer, "%d", &value);
        addProgramByte (prog, value);
    } else {
        int lPos = findLabelByName (lManager, writeBuffer);
        if (lPos != -1) {
            addProgramByte (prog, lManager->labels[lPos].value);
        } else {
            //error
        }
    }
    return 0;
}

int addJnzCode (char * errorMsg, FILE * pFile, char * writeBuffer, struct labelManager * lManager, struct program * prog) {
    addProgramByte (prog, 15);
    getNextString (writeBuffer, pFile);
    if (isDataAddress (writeBuffer)) {
        int lPos = findLabelByName(lManager, (char*)(writeBuffer + 1));
        addProgramByte (prog, lManager->labels[lPos].value);
    } else if (isNumber (writeBuffer)) {
        int value;
        sscanf (writeBuffer, "%d", &value);
        addProgramByte (prog, value);
    } else {
        int lPos = findLabelByName (lManager, writeBuffer);
        if (lPos != -1) {
            addProgramByte (prog, lManager->labels[lPos].value);
        } else {
            //error
        }
    }
    return 0;
}

